#include "Fleet.hh"
#include "Fleet/Noop.hh"
#include "../Exception.hh"
#include <algorithm>

using namespace Geom;
using namespace std;
using namespace World;

spFleet
Fleet::construct(
  u8 id,
  spPlayer owner,
  Vector< f8 > const& position,
  u8 battleship,
  u8 fighter,
  u8 transportship,
  u8 colonyship,
  u8 tank
) {
    return spFleet(new Fleet(
      id, owner, position,battleship, fighter, transportship, colonyship, tank
    ));
}

/**
 * \brief Flotta konstruktor.
 * \param id            Játékosonkénti egyedi azonosító.
 * \param position      Kezdeti hely.
 * \paran battleship    Csatahajók száma.
 * \paran fighter       Vadászok száma.
 * \paran transportship Csapatszállítók száma.
 * \paran colonyship    Kolonizáló hajók száma.
 * \paran tank          Tankok száma.
 */
Fleet::Fleet(
  u8 id,
  spPlayer owner,
  Geom::Vector< f8 > const& position,
  u8 battleship, u8 fighter, u8 transportship, u8 colonyship, u8 tank
):
    lock(QMutex::Recursive),
    id(id),
    owner(owner),
    command(spNoop(new Noop())),
    position(position),
    battleship(battleship),
    fighter(fighter),
    transportship(transportship),
    colonyship(colonyship),
    tank(tank) {}

spFleet Fleet::self() const {
    spPlayer player = owner.toStrongRef();

    if (player.isNull())
        throw NullPointerException("Fleet::self player");

    spFleet fleet = player->get_fleet(id);

    if (fleet.isNull())
        throw NullPointerException("Fleet::self fleet");

    return fleet;
}

void Fleet::destruct() {
    QMutexLocker locker(&lock);
    owner.toStrongRef()->del_fleet(id);
}

/**
 * \brief Idő léptetése.
 *
 * A flotta viselkedése az éppen aktuális parancstól függ.
 */
void Fleet::next_turn() {
//    QMutexLocker locker(&lock);
    qDebug("Fleet::next_turn pos = (%f, %f)", position.x, position.y);
    if (command->execute(self()))
        command = spCommand(new Noop());
}

/**
 * \brief Flotta mozgatása adott koordináták felé.
 * \param destination A cél koordináták.
 */
void Fleet::move_towards(Vector<> const& destination) {
    QMutexLocker locker(&lock);
    qDebug("Fleet::move_towards dest = (%f, %f)", destination.x, destination.y);
    Vector<> speed = destination - position;
    speed.set_length(min(speed.get_length(), get_speed()));
    position += speed;
}

void Fleet::attack(spFleet attacker) {
    QMutexLocker locker(&lock);
    u8 defenderStrength = 10 * battleship + fighter;
    u8 attackerStrength = 10 * attacker->get_battleship() + attacker->get_fighter();

    if (attackerStrength < defenderStrength) {
        attacker->destruct();
    } else if (attackerStrength > defenderStrength) {
        destruct();
    } else {
        attacker->destruct();
        destruct();
    }
}

/**
 * \brief Tankok maximális száma.
 */
u8 Fleet::max_tanks() const {
    QMutexLocker locker(&lock);
    return battleship + 10 * transportship;
}

/**
 * \brief Sebesség lekérdezése.
 * \return A leglassabb hajótípus sebessége.
 */
f8 Fleet::get_speed() const {
    QMutexLocker locker(&lock);

    if (colonyship)
        return 2.0;

    if (transportship)
        return 4.0;

    return 6.0;
}

/**
 * \brief Segédfüggvény a parancs kiadáshoz.
 * \see Fleet::set_command(spCommand)
 */
void Fleet::set_command(Command* newCommand) {
    set_command(spCommand(newCommand));
}

/**
 * \brief Parancs kiadása.
 *
 * Az előző parancsot törli.
 */
void Fleet::set_command(spCommand newCommand) {
    QMutexLocker locker(&lock);

    if (!newCommand)
        throw NullPointerException();

    command = newCommand;
}

WP_GETTER  (Fleet, Player,           owner)
SYNC_GETTER(Fleet, Fleet::spCommand, command)
SYNC_GETTER(Fleet, Vector<>, position)
SYNC_GETTER(Fleet, u8,       battleship)
SYNC_GETTER(Fleet, u8,       fighter)
SYNC_GETTER(Fleet, u8,       transportship)
SYNC_GETTER(Fleet, u8,       colonyship)
SYNC_GETTER(Fleet, u8,       tank)
SYNC_ADDER (Fleet, i8,       battleship)
SYNC_ADDER (Fleet, i8,       fighter)
SYNC_ADDER (Fleet, i8,       transportship)
SYNC_ADDER (Fleet, i8,       colonyship)
SYNC_ADDER (Fleet, i8,       tank)
